// throttleDirective.js
// 一些常用的自定义指令
import Vue from 'vue'

let MyPlugin = {}
// 定义全局指令
export default MyPlugin.install = function(vue, options) {
// 节流函数
  Vue.directive('throttle', {
    inserted: function (el, binding) {
      let timeoutId
      let lastExecutedTime = 0

      const {value, arg, modifiers} = binding

      const delay = modifiers.immediate ? +arg || 200 : +arg || 0

      const execute = function () {
        clearTimeout(timeoutId)
        value();
        lastExecutedTime = Date.now()
      }

      el.addEventListener('click', function () {
        const currentTime = Date.now()

        if (currentTime - lastExecutedTime >= delay) {
          execute()
        } else {
          clearTimeout(timeoutId)
          timeoutId = setTimeout(execute, delay)
        }
      })
    }
  })
// 外部点击
  Vue.directive('out-click', {
    bind: function (el, binding, vnode) {
      el.clickOutsideEvent = function (event) {
        if (!(el === event.target || el.contains(event.target))) {
          binding.value.call(this, event);
        }
      };
      document.body.addEventListener('click', el.clickOutsideEvent);
    },
    unbind: function (el) {
      document.body.removeEventListener('click', el.clickOutsideEvent);
    },
  });
// 自动聚焦
  Vue.directive('focus', {
    inserted: function (el) {
      el.focus();
    },
  });
// 图片懒加载
  Vue.directive('lazy-img', {
    inserted: function (el, binding) {
      const img = new Image();
      img.src = binding.value;

      img.onload = () => {
        el.src = binding.value;
      };
    },
  });
// 防止重复点击
  Vue.directive('noMoreClick', {
    inserted(el, binding) {
      el.addEventListener('click', () => {
        el.style.pointerEvents = 'none'
        setTimeout(() => {
          el.style.pointerEvents = ''
        }, 1000)
      })
    }
  })
// 复制到粘贴板
  Vue.directive('clipboard', {
    bind(el, binding) {
      if (binding.arg === 'success') {
        el._v_clipboard_success = binding.value
      } else if (binding.arg === 'error') {
        el._v_clipboard_error = binding.value
      } else {
        const clipboard = new Clipboard(el, {
          text() {
            return binding.value
          },
          action() {
            return binding.arg === 'cut' ? 'cut' : 'copy'
          }
        })
        clipboard.on('success', e => {
          const callback = el._v_clipboard_success
          callback && callback(e)
        })
        clipboard.on('error', e => {
          const callback = el._v_clipboard_error
          callback && callback(e)
        })
        el._v_clipboard = clipboard
      }
    },
    unbind(el, binding) {
      if (binding.arg === 'success') {
        delete el._v_clipboard_success
      } else if (binding.arg === 'error') {
        delete el._v_clipboard_error
      } else {
        el._v_clipboard.destroy()
        delete el._v_clipboard
      }
    }
  })
// 滚动加载
  Vue.directive('scroll-load', {
    inserted(el, binding) {
      const loadFunction = binding.value;
      const scrollWrapper = el;

      scrollWrapper.addEventListener('scroll', function () {
        const scrollTop = scrollWrapper.scrollTop;
        const scrollHeight = scrollWrapper.scrollHeight;
        const clientHeight = scrollWrapper.clientHeight;

        if (scrollTop + clientHeight >= scrollHeight * 0.95) {
          loadFunction();
        }
      });
    }
  });
// 动态元素高度
  Vue.directive('auto-height', {
    componentUpdated(el, binding) {
      const resize = () => {
        el.style.height = 'auto';
        el.style.height = el.scrollHeight + 'px';
      };

      el.addEventListener('input', resize);
      resize(); // 初始化时调整一次
    }
  });
// 自定义长按事件：
  Vue.directive('long-press', {
    bind(el, binding) {
      const pressTime = binding.arg;
      const pressHandler = binding.value;

      let pressTimer = null;

      const startHandler = () => {
        clearTimeout(pressTimer);
        pressTimer = setTimeout(() => {
          pressHandler();
        }, pressTime);
      };

      const stopHandler = () => {
        clearTimeout(pressTimer);
      };

      el.addEventListener('mousedown', startHandler);
      el.addEventListener('mouseup', stopHandler);
      el.addEventListener('mouseleave', stopHandler);
    },
    unbind(el) {
      el.removeEventListener('mousedown', startHandler);
      el.removeEventListener('mouseup', stopHandler);
      el.removeEventListener('mouseleave', stopHandler);
    }
  });
// 限制输入框智能输入数字
  Vue.directive('number-only', {
    bind(el) {
      function handleInput(event) {
        // 处理输入事件
        // 获取输入框的值
        const inputValue = event.target.value;
        // 将非数字字符替换为空字符串，得到格式化后的值
        const formattedValue = inputValue.replace(/[^\d]/g, '');
        // 如果原始值和格式化后的值不相等
        // 将输入框的值设置为格式化后的值
        if (inputValue !== formattedValue) {
          event.target.value = formattedValue;
          // 阻止默认行为
          event.preventDefault();
        }
      }

      el.addEventListener('input', handleInput);
      el.$_number_only_destroy = () => {
        el.removeEventListener('input', handleInput);
      };
    },
    unbind(el) {
      el.$_number_only_destroy();
    }
  });
// 触摸滑动处理
  Vue.directive('touch-swipe', {
    bind(el, binding) {
      let startX, startY, startTime;
      const handler = binding.value;
      const touchEvent = e => {
        const touch = e.touches[0];
        switch (e.type) {
          case 'touchstart':
            startX = touch.clientX;
            startY = touch.clientY;
            startTime = new Date().getTime();
            break;
          case 'touchend':
            const deltaX = touch.clientX - startX;
            const deltaY = touch.clientY - startY;
            const totalTime = new Date().getTime() - startTime;

            if (Math.abs(deltaX) > 30 && totalTime < 1000) {
              handler(deltaX > 0 ? 'right' : 'left');
            }

            if (Math.abs(deltaY) > 30 && totalTime < 1000) {
              handler(deltaY > 0 ? 'down' : 'up');
            }
            break;
        }
      };

      el.addEventListener('touchstart', touchEvent);
      el.addEventListener('touchend', touchEvent);
      el.$_touch_swipe_destroy = () => {
        el.removeEventListener('touchstart', touchEvent);
        el.removeEventListener('touchend', touchEvent);
      };
    },
    unbind(el) {
      el.$_touch_swipe_destroy();
    }
  });
// 元素拖拽
  Vue.directive('draggable', {
    bind(el) {
      let startX, startY, initialX, initialY;
      let isDragging = false;

      function handleMouseDown(event) {
        startX = event.clientX;
        startY = event.clientY;
        initialX = parseFloat(el.style.left) || 0;
        initialY = parseFloat(el.style.top) || 0;
        isDragging = true;
      }

      function handleMouseMove(event) {
        // 处理鼠标移动事件
        // 如果不处于拖拽状态，则直接返回
        if (!isDragging) return;
        // 计算鼠标移动的差值
        const deltaX = event.clientX - startX;
        const deltaY = event.clientY - startY;
        // 根据差值计算新的位置
        const newX = initialX + deltaX;
        const newY = initialY + deltaY;
        // 设置元素的新位置
        el.style.left = newX + 'px';
        el.style.top = newY + 'px';
      }

      function handleMouseUp() {
        isDragging = false;
      }

      el.addEventListener('mousedown', handleMouseDown);
      document.addEventListener('mousemove', handleMouseMove);
      document.addEventListener('mouseup', handleMouseUp);
      el.$_draggable_destroy = () => {
        el.removeEventListener('mousedown', handleMouseDown);
        document.removeEventListener('mousemove', handleMouseMove);
        document.removeEventListener('mouseup', handleMouseUp);
      };
    },
    unbind(el) {
      el.$_draggable_destroy();
    }
  });
// 自定义点击外部元素关闭模态的指令
  Vue.directive('click-outside', {
    bind: function (el, binding, vnode) {
      el.clickOutsideEvent = function (event) {
        if (!(el === event.target || el.contains(event.target))) {
          vnode.context[binding.expression](event);
        }
      };
      document.body.addEventListener('click', el.clickOutsideEvent);
    },
    unbind: function (el) {
      document.body.removeEventListener('click', el.clickOutsideEvent);
    }
  });
// 图片懒加载
  Vue.directive('lazy', {
    bind(el, binding) {
      const img = new Image();
      const color = Math.floor(Math.random() * 1000000);
      img.src = binding.value;
      el.style.backgroundColor = '#' + color;
      img.onload = function () {
        el.style.backgroundImage = 'url(' + binding.value + ')';
      }
    }
  });
// 鼠标悬停变色
  Vue.directive('hovercolor', {
    bind(el, binding, vnode) {
      el.onmouseover = function () {
        el.style.color = binding.value; // 使用绑定的值作为颜色
      }
      el.onmouseout = function () {
        el.style.color = ''; // 鼠标移出后颜色恢复
      }
    }
  });
// 文字提示
  Vue.directive('tooltip', {
    bind(el, binding, vnode) {
      var tooltip = document.createElement('div');
      tooltip.style.position = 'absolute';
      tooltip.style.bottom = '100%';
      tooltip.style.left = '0';
      tooltip.style.padding = '5px 10px';
      tooltip.style.backgroundColor = '#333';
      tooltip.style.color = '#fff';
      tooltip.style.borderRadius = '5px';
      tooltip.style.marginBottom = '10px';
      tooltip.style.opacity = '0';
      tooltip.style.transition = '0.3s';
      tooltip.innerHTML = binding.value;

      el.onmouseover = function () {
        tooltip.style.opacity = '1';
      }
      el.onmouseout = function () {
        tooltip.style.opacity = '0';
      }

      el.appendChild(tooltip);
    }
  });
// 图片预先加载
  Vue.directive('img-preload', {
    bind(el, binding, vnode) {
      var img = new Image();
      // 首先设置占位图
      el.src = 'path/to/placeholder.jpg';
      img.onload = function () {
        // 实际图片加载完成后替换
        el.src = binding.value;
      }
      // 开始加载实际图片
      img.src = binding.value;
    }
  });

  // 注册el-autocomplete框滚动底部指令
  Vue.directive('loadmore', {
    bind(el, binding) {
      // 获取element-ui定义好的scroll盒子 下拉选框滚动底部事件
      const SELECTWRAP_DOM = el.querySelector('.el-scrollbar .el-autocomplete-suggestion__wrap')
      SELECTWRAP_DOM.addEventListener('scroll', function () {
        const scrollTop = SELECTWRAP_DOM.scrollTop;
        const scrollHeight = SELECTWRAP_DOM.scrollHeight;
        const clientHeight = SELECTWRAP_DOM.clientHeight;

        if (scrollTop + clientHeight >= scrollHeight * 0.95) {
          binding.value()
        }
        // const CONDITION = scrollHeight - scrollTop <= clientHeight
        // if (CONDITION) {
        //   binding.value()
        // }
      })
    }
  })

// v-dialogDrag: 弹窗拖拽属性
  Vue.directive('dialogDrag', {
    bind(el, binding, vnode, oldVnode) {
      const dialogHeaderEl = el.querySelector('.el-dialog__header');
      const dragDom = el.querySelector('.el-dialog');

      dialogHeaderEl.style.cssText += ';cursor:move;'
      dragDom.style.cssText += ';top:0px;'

      // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
      const sty = (() => {
        if (window.document.currentStyle) {
          return (dom, attr) => dom.currentStyle[attr];
        } else {
          return (dom, attr) => getComputedStyle(dom, false)[attr];
        }
      })()

      dialogHeaderEl.onmousedown = (e) => {
        // 鼠标按下，计算当前元素距离可视区的距离
        const disX = e.clientX - dialogHeaderEl.offsetLeft;
        const disY = e.clientY - dialogHeaderEl.offsetTop;

        const screenWidth = document.body.clientWidth; // body当前宽度
        const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度，可某些环境下无法获取)

        const dragDomWidth = dragDom.offsetWidth; // 对话框宽度
        const dragDomheight = dragDom.offsetHeight; // 对话框高度

        const minDragDomLeft = dragDom.offsetLeft;
        const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth;

        const minDragDomTop = dragDom.offsetTop;
        const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight;


        // 获取到的值带px 正则匹配替换
        let styL = sty(dragDom, 'left');
        let styT = sty(dragDom, 'top');

        // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
        if (styL.includes('%')) {
          styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100);
          styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100);
        } else {
          styL = +styL.replace(/\px/g, '');
          styT = +styT.replace(/\px/g, '');
        };

        document.onmousemove = function (e) {
          // 通过事件委托，计算移动的距离
          let left = e.clientX - disX;
          let top = e.clientY - disY;

          // 边界处理
          if (-(left) > minDragDomLeft) {
            left = -(minDragDomLeft);
          } else if (left > maxDragDomLeft) {
            left = maxDragDomLeft;
          }

          if (-(top) > minDragDomTop) {
            top = -(minDragDomTop);
          } else if (top > maxDragDomTop) {
            top = maxDragDomTop;
          }

          // 移动当前元素
          dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
        };

        document.onmouseup = function (e) {
          document.onmousemove = null;
          document.onmouseup = null;
        };
      }
    }
  })

}
